const { HNSWLib } = require("@langchain/community/vectorstores/hnswlib");
const { Embeddings } = require("@langchain/core/embeddings");
const { RecursiveCharacterTextSplitter } = require("@langchain/textsplitters");
const axios = require("axios");
const path = require('path');
const fs = require('fs');

// 自定义嵌入类，使用模拟向量（因为DeepSeek不提供嵌入API）
class DeepSeekEmbeddings extends Embeddings {
    constructor(fields) {
        super(fields || {});
        // 注意：DeepSeek不提供嵌入API，只提供聊天API
        // 我们使用固定维度的随机向量作为模拟
        console.log("警告：使用模拟向量，因为DeepSeek不提供嵌入API");
    }

    async embedDocuments(texts) {
        // 对于每个文本，生成嵌入向量
        const embeddings = [];
        for (const text of texts) {
            const embedding = await this.embedQuery(text);
            embeddings.push(embedding);
        }
        return embeddings;
    }

    async embedQuery(text) {
        try {
            console.log(`为文本生成嵌入向量: ${text.substring(0, 50)}...`);
            
            // 返回固定维度的随机向量（模拟嵌入）
            // 使用固定种子确保相同文本生成相同向量
            const seed = this.hashCode(text);
            const vector = Array.from({ length: 1536 }, (_, i) => {
                // 使用简单的伪随机数生成器
                const x = Math.sin(seed + i) * 10000;
                return x - Math.floor(x);
            });
            
            return vector;
        } catch (error) {
            console.error("生成模拟向量失败:", error.message);
            // 如果生成失败，返回随机向量
            console.log("使用随机向量作为后备方案");
            return Array.from({ length: 1536 }, () => Math.random());
        }
    }
    
    // 简单的哈希函数，用于生成确定性的伪随机数
    hashCode(str) {
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            const char = str.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash = hash & hash; // 转换为32位整数
        }
        return Math.abs(hash);
    }
}

// 导出DeepSeekEmbeddings类
module.exports.DeepSeekEmbeddings = DeepSeekEmbeddings;

const VECTOR_STORE_PATH = path.join(__dirname, '../vector_store');

// 确保向量存储目录存在
if (!fs.existsSync(VECTOR_STORE_PATH)) {
    console.log(`向量存储目录不存在，尝试创建: ${VECTOR_STORE_PATH}`);
    try {
        fs.mkdirSync(VECTOR_STORE_PATH, { recursive: true });
        console.log('向量存储目录创建成功');
    } catch (err) {
        console.error('创建向量存储目录失败:', err);
    }
}

// 初始化阿里云的Embedding模型
const { AliyunEmbeddings } = require('./aliyunEmbeddings');
const embeddings = new AliyunEmbeddings();

// 文本分割器
const textSplitter = new RecursiveCharacterTextSplitter({
    chunkSize: 500,  // 每个文本块的最大长度
    chunkOverlap: 50, // 块之间的重叠长度，保证语义连续性
});

/**
 * 将单个知识点的内容添加到向量数据库中
 * @param {object} knowledgePoint - 包含 _id 和 content 的知识点对象
 */
exports.addKnowledgePointToStore = async (knowledgePoint) => {
    try {
        console.log(`正在为知识点 ${knowledgePoint._id} 创建向量...`);

        // 1. 分割文本
        const docs = await textSplitter.createDocuments(
            [knowledgePoint.content], // 接收一个字符串数组
            [{ knowledgePointId: knowledgePoint._id.toString() }] // 为每个文档块添加元数据
        );

        console.log(`知识点被分割成 ${docs.length} 个文本块。`);
        
        // 2. 检查向量数据库是否存在，如果存在则加载并添加，否则新建
        let vectorStore;
        try {
            // 尝试加载已存在的存储
            console.log(`尝试从 ${VECTOR_STORE_PATH} 加载向量存储...`);
            vectorStore = await HNSWLib.load(VECTOR_STORE_PATH, embeddings);
            await vectorStore.addDocuments(docs);
            console.log('向已存在的向量库中添加了新文档。');
        } catch (e) {
            // 如果加载失败（比如文件不存在），则创建一个新的
            console.log('未找到向量库，正在创建新的...', e.message);
            vectorStore = await HNSWLib.fromDocuments(docs, embeddings);
        }

        // 3. 保存向量数据库到本地文件
        await vectorStore.save(VECTOR_STORE_PATH);
        console.log(`知识点 ${knowledgePoint._id} 的向量已成功保存。`);

    } catch (error) {
        console.error('添加到向量库失败:', error);
    }
};

/**
 * 从向量数据库中搜索相关知识点
 * @param {string} query - 查询文本
 * @param {number} k - 返回最相似的k个结果
 */
exports.searchKnowledgePoints = async (query, k = 4) => {
    try {
        console.log(`尝试从 ${VECTOR_STORE_PATH} 加载向量存储进行搜索...`);
        // 加载向量数据库
        const vectorStore = await HNSWLib.load(VECTOR_STORE_PATH, embeddings);
        
        // 执行相似度搜索
        const results = await vectorStore.similaritySearch(query, k);
        
        return results;
    } catch (error) {
        console.error('向量搜索失败:', error);
        return [];
    }
};